pub mod file;
pub mod error;
pub mod rechunk;
pub mod statistics;

pub use file::*;
pub use error::*;
pub use rechunk::*;
pub use statistics::*;

use crate::{recipe::{ChunkPointer, VersionControlBlock, VersionFrom}, constants::VERSION_DIR_NAME};
use pipelines::Pipeline;
use std::{path::Path, time::Instant};
use std::fmt::Debug;
use std::sync::Arc;
use parking_lot::Mutex;

use crate::constants::CONTAINER_FILE_NAME;

pub fn restore<T:ChunkPointer+Send+Debug+'static,P: AsRef<Path>+?Sized>(compress_path:&P,restore_path:&P,version:Option<VersionFrom>) 
								-> RestoreResult<Arc<Mutex<RestoreStatistics>>> {
	let statistics = Arc::new(Mutex::new(RestoreStatistics::new()));
	let version_dir_name = compress_path.as_ref().to_path_buf().join(VERSION_DIR_NAME);
	let vcb = VersionControlBlock::from_path(version_dir_name.to_str().unwrap())?;
	let recipe_dir_name = match &version {
		Some(version) => {
			vcb.seek_version(version.clone())?
		}
		None => {
			vcb.default_version()?
		}
	}.map_or(Err(RestoreError::VersionMissing(version)), |dir|Ok(dir))?;
	
	drop(vcb);
	let compress_path = compress_path.as_ref();
	let restore_path = restore_path.as_ref().to_path_buf();

	let container_path = compress_path.join(CONTAINER_FILE_NAME);
	let recipe_path = compress_path.join(recipe_dir_name);

	let collector = RestoreErrorCollector::new();
	let collector1 = collector.clone();
	let collector2 = collector.clone();
	let rechunker = ReChunker::from_path(&container_path,statistics.clone());
	let file_builder = FileBuilder::from_path(&recipe_path,&restore_path,statistics.clone())?;
	let now = Instant::now();
	Pipeline::new(move |out|{
				collector1.collect(file_builder.build_async::<T>(&out));
			}).end(move |recv|{
				collector2.collect(rechunker.rechunk_async(recv))
			})?;
	let total_time = now.elapsed().as_micros();
	statistics.lock().set_total_time(total_time);
	collector.try_return(statistics)
}
